package com.maxd.service.evaluation;

import com.fasterxml.jackson.core.type.TypeReference;
import com.google.common.collect.Lists;
import com.maxd.adapter.LoginUserHolder;
import com.maxd.bean.PageRes;
import com.maxd.bean.evaluation.EvaluationData;
import com.maxd.bean.evaluation.EvaluationReq;
import com.maxd.error.ExceptionEnum;
import com.maxd.model.ClassLessonInfo;
import com.maxd.model.EvaluationRecord;
import com.maxd.model.MedalSendRec;
import com.maxd.model.StudentInfo;
import com.maxd.respository.ClassLessonInfoRepository;
import com.maxd.respository.EvaluationRecordRepository;
import com.maxd.respository.MedalSendRecRepository;
import com.maxd.respository.StudentInfoRepository;
import com.maxd.utils.AssertUtil;
import com.maxd.utils.JsonUtils;
import com.maxd.utils.PageUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Predicate;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class EvaluationService implements IEvaluationService {

    private static final Logger log = LoggerFactory.getLogger(EvaluationService.class);
    @Autowired
    private ClassLessonInfoRepository classLessonInfoRepository;

    @Autowired
    private EvaluationRecordRepository evaluationRecordRepository;

    @Autowired
    private StudentInfoRepository studentInfoRepository;

    @Autowired
    private MedalSendRecRepository medalSendRecRepository;

    @Override
    public List<StudentInfo> waitEvaluationList(Long lessonId) {
        Long userId = LoginUserHolder.getUserId();
        AssertUtil.assertTrue(userId != null && userId > 0, ExceptionEnum.WRONT_TOKEN);

        ClassLessonInfo lessonInfo = classLessonInfoRepository.findById(lessonId).orElse(null);
        AssertUtil.notNull(lessonInfo, ExceptionEnum.LESSON_NOT_EXISTS);
        AssertUtil.assertTrue(userId.equals(lessonInfo.getInstructorUserId()) || userId.equals(lessonInfo.getAssistantUserId()), ExceptionEnum.PRIVILEGE_ERROR);
        // 获取签到的学生列表
        String signStudents = lessonInfo.getSignStudents();
        if (StringUtils.isEmpty(signStudents)) {
            return Lists.newArrayList();
        }
        List<Long> studentIds = JsonUtils.parseObject(signStudents, new TypeReference<List<Long>>() {
        });
        if(CollectionUtils.isEmpty(studentIds)) {
            return Lists.newArrayList();
        }
        // 查询评价记录，筛选未评价的记录
        Set<Long> doneIds = queryList(lessonId, null, null).stream().map(EvaluationRecord::getStudentId).collect(Collectors.toSet());
        List<Long> notDoneIds = studentIds.stream().filter(e -> !doneIds.contains(e)).collect(Collectors.toList());

        return studentInfoRepository.findAllById(notDoneIds);
    }

    @Override
    @Transactional
    public void batchEvaluation(EvaluationReq req) {
        Long userId = LoginUserHolder.getUserId();
        AssertUtil.assertTrue(userId != null && userId > 0, ExceptionEnum.WRONT_TOKEN);

        ClassLessonInfo lessonInfo = classLessonInfoRepository.findById(req.getLessonId()).orElse(null);
        AssertUtil.notNull(lessonInfo, ExceptionEnum.LESSON_NOT_EXISTS);
        AssertUtil.assertTrue(userId.equals(lessonInfo.getInstructorUserId()) || userId.equals(lessonInfo.getAssistantUserId()), ExceptionEnum.PRIVILEGE_ERROR);
        // 查询已评价的记录
        Map<Long, EvaluationRecord> doneMap = queryList(req.getLessonId(), null, null).stream().collect(Collectors.toMap(e -> e.getStudentId(), e -> e, (e1, e2) -> e1));
        // 逐一处理评价
        List<EvaluationRecord> evaluationRecords = Lists.newArrayList();
        List<MedalSendRec> medalSendRecs = Lists.newArrayList();
        for (EvaluationData evaluationData : req.getEvaluationList()) {
            // 评价记录
            EvaluationRecord evaluationRecord = new EvaluationRecord();
            evaluationRecord.setLessonId(req.getLessonId());
            evaluationRecord.setStudentId(evaluationData.getStudentId());
            evaluationRecord.setEvaluationContent(evaluationData.getContent());
            evaluationRecord.setScore(evaluationData.getScore());
            evaluationRecord.setEvaluationUserId(userId);
            evaluationRecord.setCreateBy(String.valueOf(userId));
            evaluationRecord.setUpdateBy(String.valueOf(userId));
            EvaluationRecord doneRec = doneMap.get(evaluationData.getStudentId());
            if(doneRec != null) {
                log.info("此记录已评价，更新评价信息，lessonId = {}, evaluationData = {}", req.getLessonId(), JsonUtils.toJsonString(evaluationData));
                evaluationRecord.setId(doneRec.getId());
            }
            evaluationRecords.add(evaluationRecord);
            // 勋章记录
            if(!CollectionUtils.isEmpty(evaluationData.getMedalIds())) {
                for (Long medalId : evaluationData.getMedalIds()) {
                    MedalSendRec medalSendRec = new MedalSendRec();
                    medalSendRec.setMedalId(medalId);
                    medalSendRec.setStudentId(evaluationData.getStudentId());
                    medalSendRec.setGrantUserId(userId);
                    medalSendRec.setCreateBy(String.valueOf(userId));
                    medalSendRec.setUpdateBy(String.valueOf(userId));
                    medalSendRecs.add(medalSendRec);
                }
            }
        }
        evaluationRecordRepository.saveAll(evaluationRecords);
        medalSendRecRepository.saveAll(medalSendRecs);
    }

    @Override
    public PageRes<EvaluationRecord> queryPage(Integer pageNo, Integer pageSize, Long lessonId, Long studentId, Long userId) {
        Sort.Order order = new Sort.Order(Sort.Direction.DESC, "createTime");
        Pageable pageable = PageRequest.of(pageNo, pageSize, Sort.by(order));
        Specification<EvaluationRecord> condition = buildCondition(lessonId, studentId, userId);
        Page<EvaluationRecord> pageList = evaluationRecordRepository.findAll(condition, pageable);
        return PageUtils.toPageRes(pageList);
    }

    @Override
    public List<EvaluationRecord> queryList(Long lessonId, Long studentId, Long userId) {
        Sort sort = Sort.by(Sort.Direction.DESC, "createTime");
        Specification<EvaluationRecord> condition = buildCondition(lessonId, studentId, userId);
        return evaluationRecordRepository.findAll(condition, sort);
    }

    private Specification<EvaluationRecord> buildCondition(Long lessonId, Long studentId, Long userId) {
        Specification<EvaluationRecord> queryCondition = (root, query, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            if(lessonId != null) {
                predicates.add(criteriaBuilder.equal(root.get("lessonId"), lessonId));
            }
            if(studentId != null) {
                predicates.add(criteriaBuilder.equal(root.get("studentId"), studentId));
            }
            if(userId != null) {
                predicates.add(criteriaBuilder.equal(root.get("evaluationUserId"), userId));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };
        return queryCondition;
    }
}
